package indi.yangshenhui.common.grpc.client;

import java.util.concurrent.TimeUnit;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import indi.yangshenhui.common.grpc.HelloReply;
import indi.yangshenhui.common.grpc.HelloRequest;
import indi.yangshenhui.common.grpc.HelloWorldGrpc;
import io.grpc.ManagedChannel;
import io.grpc.ManagedChannelBuilder;
import io.grpc.StatusRuntimeException;

public class HelloWorldClient {
	private static final Logger log = LoggerFactory.getLogger(HelloWorldClient.class);

	private final ManagedChannel channel;
	public final HelloWorldGrpc.HelloWorldBlockingStub blockingStub;
	public final HelloWorldGrpc.HelloWorldFutureStub futureStub;
	public final HelloWorldGrpc.HelloWorldStub asyncStub;

	public HelloWorldClient(String host, int port) {
		channel = ManagedChannelBuilder.forAddress(host, port).usePlaintext(true).build();
		blockingStub = HelloWorldGrpc.newBlockingStub(channel);
		futureStub = HelloWorldGrpc.newFutureStub(channel);
		asyncStub = HelloWorldGrpc.newStub(channel);
	}

	public void shutdown() throws InterruptedException {
		channel.shutdown().awaitTermination(5, TimeUnit.SECONDS);
	}

	public static void main(String[] args) throws Exception {
		HelloWorldClient client = new HelloWorldClient("localhost", 50051);
		try {
			String name = "world";
			if (args.length > 0) {
				name = args[0];
			}
			// sayHello
			HelloRequest request = HelloRequest.newBuilder().setName(name).build();
			HelloReply response;
			try {
				response = client.blockingStub.withCompression("gzip").sayHello(request);
			} catch (StatusRuntimeException e) {
				log.error("RPC failed: {}", e.getStatus());
				return;
			}
			log.info("RPC response: " + response.getMessage());
			
			// sayHello2
			/*Iterator<HelloReply> responseIterator = client.blockingStub.sayHello2(request);
			if (responseIterator != null) {
				while (responseIterator.hasNext()) {
					HelloReply helloReply = responseIterator.next();
					log.info("RPC response: " + helloReply.getMessage());
				}
			}*/
			
			// sayHello3
			/*final CountDownLatch finishLatch = new CountDownLatch(1);
			StreamObserver<HelloReply> responseObserver = new StreamObserver<HelloReply>() {
				
				@Override
				public void onNext(HelloReply arg0) {
					log.info("RPC response: " + arg0.getMessage());
				}
				
				@Override
				public void onError(Throwable arg0) {
					log.error(arg0.getMessage(), arg0);
				}
				
				@Override
				public void onCompleted() {
					log.info("Finished sayHello3");
					finishLatch.countDown();
				}
				
			};
			StreamObserver<HelloRequest> requestObserver = client.asyncStub.sayHello3(responseObserver);
			try {
				for (int i = 1; i <= 10; ++i) {
					HelloRequest request2 = HelloRequest.newBuilder().setName(name+i).build();
					requestObserver.onNext(request2);
					if (finishLatch.getCount() == 0) {
						return;
					}
				}
			} catch (RuntimeException e) {
				requestObserver.onError(e);
				throw e;
			}
			requestObserver.onCompleted();
			finishLatch.await(1, TimeUnit.MINUTES);*/
			
			// sayHello4
			/*final CountDownLatch finishLatch = new CountDownLatch(1);
			StreamObserver<HelloReply> responseObserver = new StreamObserver<HelloReply>() {
				
				@Override
				public void onNext(HelloReply arg0) {
					log.info("RPC response: " + arg0.getMessage());
				}
				
				@Override
				public void onError(Throwable arg0) {
					log.error(arg0.getMessage(), arg0);
				}
				
				@Override
				public void onCompleted() {
					log.info("Finished sayHello3");
					finishLatch.countDown();
				}
				
			};
			StreamObserver<HelloRequest> requestObserver = client.asyncStub.sayHello4(responseObserver);
			try {
				for (int i = 1; i <= 10; ++i) {
					HelloRequest request2 = HelloRequest.newBuilder().setName(name+i).build();
					requestObserver.onNext(request2);
					if (finishLatch.getCount() == 0) {
						return;
					}
				}
			} catch (RuntimeException e) {
				requestObserver.onError(e);
				throw e;
			}
			requestObserver.onCompleted();
			finishLatch.await(1, TimeUnit.MINUTES);*/
			
		} catch (Exception e) {
			log.error(e.getMessage(), e);
		} finally {
			client.shutdown();
		}
	}
}
